package com.example.demo.util;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.example.demo.core.DefineConstant;
import com.example.demo.entity.LoginEnity;

import cn.hutool.core.util.IdUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class RedisUtil {
	@Autowired
	private RedisTemplate<String, String> redisTemplate;
	
	/**
	 * 获取hash类型数据中单个键的值
	 * @param hashname
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public String getSingleHashValue(String hashname,String key) throws Exception{
		HashOperations<String, String, String> hash = redisTemplate.opsForHash();
		
		return hash.get(hashname, key);
	}
	
	/**
	 * 获取hash类型的所有键值对
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public Map<String, Object> getHashValue(String key) throws Exception{
		if(hashKey(key)) {
			 HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
			 
			 return hashOperations.entries(key);
		}
		return null;
	}
	
	/**
	 * 获取list类型的数据类型
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public List<String> getListValue(String key) throws Exception{
		if(hashKey(key)) {
			ListOperations<String, String> listOperations = redisTemplate.opsForList();
			
			return listOperations.range(key, 0, -1);
		}
		
		return null;
	}
	
	/**
	 * 获取字符串类型键值
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public String getValue(String key) throws Exception{
		ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
		if(hashKey(key)) {
			return valueOperations.get(key);
		}
		return null;
	}
	
	/**
	 * 修改hash类型数据中单个键值对的值
	 * @param key
	 * @param hashkey
	 * @param value
	 * @throws Exception
	 */
	public void updateSingleHashVluae(String key,String hashkey,Object value) throws Exception{
		HashOperations<String, String, Object> hash = redisTemplate.opsForHash();
		
		hash.put(key, hashkey, value);
	}
	
	/**
	 * 设置hash类型数据
	 * @param key
	 * @param mapValue
	 * @param timeout
	 * @throws Exception
	 */
	public void addHashValue(String key,Map<String, String> mapValue,Long timeout) throws Exception{
		 HashOperations<String, String, Object> hash = redisTemplate.opsForHash();
		 
		 Set<String> keys = mapValue.keySet();
		 
		 for (String hashkey : keys) {
			 hash.put(key, hashkey, mapValue.get(hashkey));
		 }
		 
		 if(null!=timeout) {
			 redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
		 }
	}
	
	/**
	 * 添加数据类型的值
	 * @param key
	 * @param list
	 * @param timeout
	 * @throws Exception
	 */
	public void addList(String key,List<String> listValue,Long timeout) throws Exception{
		ListOperations<String, String> listOperations = redisTemplate.opsForList();
		
		listOperations.rightPushAll(key, listValue);
		
		if(null!=timeout) {
			redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
		}
		
	}
	
	/**
	 * 添加字符串类型的值
	 * @param key
	 * @param value
	 * @throws Exception
	 */
	public void addString(String key,String value,Long timeout) throws Exception {
		ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
		
		valueOperations.set(key, value);
		
		if(null!=timeout) {
			redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
		}
	}
	
	/**
	 * @return
	 * @创建时间: 2019年8月28日
	 * @创建人: 许子文
	 * @功能描述: 验证token是否存在redis中,如果有的话则刷新token时间
	 */
	public boolean checkToken(String token) throws Exception {
		String tokenKey = assemblyTokenKey(token);
		
		if(hashKey(tokenKey)) {
			
			Long defualtTokenTime = Long.parseLong(PropertiesUtil.getProperty("tokenTimeOut"));
			
			redisTemplate.expire(token, defualtTokenTime, TimeUnit.SECONDS);
			
			return true;
		}
		
		return false;
	}
	
	/**
	 * 设置token
	 * @创建者 xzw
	 * @创建日期 2025年5月13日
	 * @返回类型 void
	 * @功能描述 
	 *
	 */
	public void setToken(String token,String value, Long timeout) throws Exception {
		String tokenKey = assemblyTokenKey(token);
		addString(tokenKey, value, timeout);
	}
	
	/**
	 * 根据token获取登录信息
	 * @创建者 xzw
	 * @创建日期 2025年5月13日
	 * @返回类型 LoginEnity
	 * @功能描述 
	 *
	 */
	public LoginEnity getLoginInfoByToken(String token) throws Exception {
		String tokenKey = assemblyTokenKey(token);
		
		String loginInfoStr = getValue(tokenKey);
		
		if(null!=loginInfoStr) {
			LoginEnity loginInfo = JSON.parseObject(loginInfoStr, LoginEnity.class);
			return loginInfo;
		} 
		
		return null;
	}
	
	/**
	 * 删除token
	 * @创建者 xzw
	 * @创建日期 2025年5月13日
	 * @返回类型 void
	 * @功能描述 
	 *
	 */
	public void removeToken(String token) throws Exception {
		String tokenKey = assemblyTokenKey(token);
		remove(tokenKey);
	}
	
	private String assemblyTokenKey(String token) {
		String tokenKey = DefineConstant.REDIS_TOKEN_PRE + token;
		return tokenKey;
	}
	
	/**
	 * 批量删除键值
	 * @param keys
	 * @throws Exception
	 */
	public void batchRemove(List<String> keys) throws Exception{
		redisTemplate.delete(keys);
	}
	
	/**
	 * 删除单个键值
	 * @param key
	 * @throws Exception
	 */
	public void remove(String key) throws Exception{
		if(hashKey(key)) {
			redisTemplate.delete(key);
		}
	}
	
	/**
	 * 判断是否存在键
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public boolean hashKey(String key) throws Exception{
		return redisTemplate.hasKey(key);
	}
	
	/**
	 * 获取redis锁
	 * @创建者 xzw
	 * @创建日期 2025年5月15日
	 * @返回类型 boolean
	 * @功能描述 
	 * @param lockKey redis中锁的key
	 * @param lockTimeout 锁默认的过期时间 单位:秒
	 * @param waitLockTime 等待锁释放的时间 单位:秒
	 *
	 */
	public boolean getLock(String lockKey,long lockTimeout,Long waitLockTime) throws Exception {
		Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, IdUtil.fastSimpleUUID(), lockTimeout, TimeUnit.SECONDS);
		
		if(!lock && waitLockTime != null && waitLockTime > 0) {
			Thread.sleep(waitLockTime*1000);
			lock = redisTemplate.opsForValue().setIfAbsent(lockKey, IdUtil.fastSimpleUUID(), lockTimeout, TimeUnit.SECONDS);
		}
		
		return lock;
	}
	
	/**
	 * 释放redis锁
	 * @创建者 xzw
	 * @创建日期 2025年5月15日
	 * @返回类型 void
	 * @功能描述 
	 *
	 */
	public void unLock(String lockKey) {
		try {
			if(hashKey(lockKey)) {
				remove(lockKey);
			}
		} catch (Exception e) {
			log.error("释放redis锁失败",e);
		}
	}
}
